package compiler;

import java.util.ArrayList;

import compiler.Exceptions.OutOfLimitsException;
import compiler.Exceptions.SyntaxErrorException;

public class Metodos
{
	private static String string = null;
	private static Tabla tabla_simbolos = new Tabla();
	private static Integer yylval = -1;
	private static int indexString = 0;
	public static ArrayList<String> ListaVariables; 
	public static boolean cargar;
	
	// Operadores
	public final static Integer OPSUMA=257;
	public final static Integer OPRESTA=258;
	public final static Integer OPMULT=259;
	public final static Integer OPDIV=260;
	public final static Integer CONCAT=261;
	public final static Integer OPASIGN=262;

	// Operadores logicos
	public final static Integer MAYOR=263;
	public final static Integer MENOR=264;
	public final static Integer MAYORIGUAL=265;
	public final static Integer MENORIGUAL=266;
	public final static Integer IGUALIGUAL=267;
	public final static Integer DISTINTO=268;

	// Terminales
	public final static Integer ID=269;
	public final static Integer CTESTRING=270;
	public final static Integer CTE=271;
	public final static Integer PYC=272;
	public final static Integer DOSPUNTOS=273;
	public final static Integer COMA=274;
	public final static Integer INIPAREN=275;
	public final static Integer FINPAREN=276;
	public final static Integer INICOR=277;
	public final static Integer FINCOR=278;
	public final static Integer GUIONBAJO=279;
	public final static Integer INILLAVE=280;
	public final static Integer FINLLAVE=281;
	
	// Limites
	private static final Integer MIN_INT 	= -32768;
	private static final Integer MAX_INT 	= 32767;
	private static final Integer MAX_REAL 	= 7;
	private static final Integer STR_MAX_L 	= 30;
	private static boolean esToken = false;
		
	// Revisa Words
	public int check_reservadas(String input)
	{
		Words token_palabra_r = Words.buscar(input);
		if(token_palabra_r != null)
			return token_palabra_r.getNumero();
		else
			return 0;
	}
	
	public int check_reservadas(int input)
	{
		Words token_palabra_r = Words.buscar(input);
		if(token_palabra_r != null)
			return token_palabra_r.getNumero();
		else
			return 0;
	}
	
	public int getYylval()
	{
		return yylval;
	}
	
	public Integer iniParA(Integer c)
	{
		return null;
	}
	
	public Integer finParA(Integer c)
	{
		return INIPAREN;
	}
	
	public Integer iniCorA(Integer c)
	{
		return null;
	}
	
	public Integer finCorA(Integer c)
	{
		return INICOR;
	}
	
	public Integer iniParC(Integer c)
	{
		return null;
	}
	
	public Integer finParC(Integer c)
	{
		return FINPAREN;
	}
	
	public Integer iniCorC(Integer c)
	{
		return null;
	}
	
	public Integer finCorC(Integer c)
	{
		return FINCOR;
	}
	
	public Integer iniPyC(Integer c)
	{
		return null;
	}
	
	public Integer finPyC(Integer c)
	{
		return PYC;
	}
	
	public Integer iniID(Integer c)
	{
		string = new String();
		string += (char) c.intValue();
		return null;
	}
	
	public Integer contID(Integer c)
	{
		string += (char) c.intValue();
		return null;
	}
	
	public Integer finID(Integer c) throws OutOfLimitsException
	{
		if(string.length() > STR_MAX_L)
			throw new OutOfLimitsException(string);
		Integer tok = null;
		Integer palabra = check_reservadas(string);
		
		if(palabra == 0)
		{ // No es palabra reservada
			Token token = new Token();
			token.setNombre(string + "_v");
			
			tabla_simbolos.agregar(token);
			yylval = tabla_simbolos.posicion(token);
			
			tok = ID;
			esToken = true;
			
			if(cargar)
				ListaVariables.add(string);
		} 
		
		else 
		{
			tok = palabra;
			
			if(tok == 289)
			{
				ListaVariables = new ArrayList<>();
				cargar = true;
			}
			
			else
				if(tok == 290)
					cargar = false;
		}
			
		string = null;
		
		return tok;
	}
	
	public Integer iniDosP(Integer c)
	{
		return null;
	}
	
	public Integer finDosP(Integer c)
	{
		return DOSPUNTOS;
	}
	
	/* Metodo que se deja por simplicidad del codigo*/
	public Integer Nada(Integer c)
	{
		return null;
	}
	
	public Integer iniComa(Integer c)
	{
		return null;
	}
	
	public Integer finComa(Integer c)
	{
		return COMA;
	}
	
	public Integer iniResta(Integer c)
	{
		return null;
	}
	
	public Integer finResta(Integer c)
	{
		return OPRESTA;
	}
	
	public Integer iniProd(Integer c)
	{
		return null;
	}
	
	public Integer finProd(Integer c)
	{
		return OPMULT;
	}
	
	public Integer finAsig(Integer c)
	{
		return OPASIGN;
	}
	
	public Integer iniString(Integer c)
	{
		string = new String();
		return null;
	}
	
	public Integer finString(Integer c)
	{
		Token token = new Token();
		String a = "_" + string;
		a = a.replaceAll(" ", "_");
		a = a.replaceAll("[\\W]","_")+"_s"+ indexString++;
		
		token.setNombre(a);
		token.setTipo("cteSTRING");
		token.setValor(string);
		token.setLongitud(string.length());
		
		tabla_simbolos.agregar(token);
		yylval = tabla_simbolos.posicion(token);
		
		string = null;
		esToken = true;
		return CTESTRING;
	}
	
	public Integer contString(Integer c) throws OutOfLimitsException
	{
		if (string.length()+1 < STR_MAX_L)
			string += (char) c.intValue();
			
		else	
			throw new OutOfLimitsException(string);
		
		return null;	
	}
	
	public Integer iniReal(Integer c)
	{
		if(string == null)
			string = "";
		string += (char) c.intValue();
		return null;
	}
	
	public Integer finReal(Integer c) throws OutOfLimitsException, SyntaxErrorException
	{
		if (string.length() -1 <= MAX_REAL)
		{
			if(string.equals("."))
				throw new SyntaxErrorException('.');
			Token token = new Token();
			if(string.endsWith("."))
				string += "0";
			if(string.startsWith("."))
				string = "0" + string;
			String a = "_" + string;
			token.setNombre(a.replaceAll("\\.", "_"));
			token.setTipo("cteFLOAT");
			token.setValor(string);
			
			tabla_simbolos.agregar(token);
			yylval = tabla_simbolos.posicion(token);
			
			string = null;
			esToken = true;
			return CTE;
		}
		
		else	
			throw new OutOfLimitsException(string);
		
	}
	
	public Integer contReal(Integer c)
	{
		string += (char) c.intValue();
		return null;
	}
	
	public Integer iniMenorIgual(Integer c)
	{
		return null;
	}
	
	public Integer finMenorIgual(Integer c)
	{
		return MENORIGUAL;
	}
	
	public Integer iniMayorIgual(Integer c)
	{
		return null;
	}
	
	public Integer finMayorIgual(Integer c)
	{
		return MAYORIGUAL;
	}
	
	public Integer iniSum(Integer c)
	{
		return null;
	}
	
	public Integer finSum(Integer c)
	{
		return OPSUMA;
	}
	
	public Integer iniGuionBajo(Integer c)
	{
		return null;
	}
	
	public Integer finGuionBajo(Integer c)
	{
		return GUIONBAJO;
	}
	
	public Integer iniComp(Integer c)
	{
		return null;
	}
	
	public Integer finComp(Integer c)
	{
		return IGUALIGUAL;
	}
	
	public Integer iniMenor(Integer c)
	{
		return null;
	}
	
	public Integer finMenor(Integer c)
	{
		return MENOR;
	}
	
	public void Error(Integer c) throws SyntaxErrorException
	{
		throw new SyntaxErrorException((char) c.intValue());
	}
	
	public Integer iniMayor(Integer c)
	{
		return null;
	}
	
	public Integer finMayor(Integer c)
	{
		return MAYOR;
	}
	
	public Integer finConcat(Integer c)
	{
		return CONCAT;
	}
	
	public Integer iniEnt(Integer c)
	{
		string = new String();
		string += (char) c.intValue();
		return null;
	}
	
	public Integer finEnt(Integer c) throws OutOfLimitsException
	{
		int val = Integer.valueOf(string);
		if(val > MIN_INT && val < MAX_INT)
		{
			Token token = new Token();
			token.setNombre("_" + string);
			token.setTipo("cteINT");
			token.setValor(string);
			
			tabla_simbolos.agregar(token);
			yylval = tabla_simbolos.posicion(token);
			
			string = null;
			esToken = true;
			return CTE;
		} 
		
		else	
			throw new OutOfLimitsException(string);
	}
	
	public Integer contEnt(Integer c)
	{
		string += (char) c.intValue();
		return null;
	}
	
	public Integer iniDiv(Integer c)
	{
		return null;
	}
	
	public Integer finDiv(Integer c)
	{
		return OPDIV;
	}
	
	public Integer iniLlaveA(Integer c)
	{
		return null;
	}
	
	public Integer finLlaveA(Integer c)
	{
		return INILLAVE;
	}
	
	public Integer iniLlaveC(Integer c)
	{
		return null;
	}
	
	public Integer finLlaveC(Integer c)
	{
		return FINLLAVE;
	}
	
	public Integer iniDistinto(Integer c)
	{
		return null;
	}
	
	public Integer finDistinto(Integer c)
	{
		return DISTINTO;
	}

	public static Tabla getTabla_simbolos()
	{
		return tabla_simbolos;
	}
	
	public static String normalizar(char c)
	{
		String ret = "";
		ret += c;
		switch(c)
		{
			case '\n':
				return "\\n";
			case '\t':
				return "\\t";
			case '\r':
				return "\\r";
			case ' ':
				return "' '";
			default:
				return ret;
		}
	}

	public boolean esToken()
	{
		boolean ret = esToken;
		esToken = false;
		return ret;
	}
}
